﻿#define debuglog

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Threading;

using RequestList = System.Collections.Generic.List<Cabal.Kernel.Output.RequestItem>; //List of Request
using TargetRequest = System.Collections.Generic.Dictionary<string, Cabal.Kernel.Output.IPTRegister>; //Dictionary of Uri to RequestList
using RequestIPList = System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<string, Cabal.Kernel.Output.IPTRegister>>; //dictionary of ip to TargetRequest
using TargetMaxNum = System.Collections.Generic.Dictionary<string, int>;
using Missions = System.Collections.Generic.Dictionary<System.Threading.Thread, Cabal.Kernel.Output.RequestItem>;

//RequestIPList[RequestIP][TargetUri] = RequestList



namespace Cabal.Kernel.Output
{
    //任务：管理请求注册列表和请求队列
    public class RequestManager : IDisposable
    {
        public RequestManager(CabalSoul kernel)
        {
            _kernel = kernel;

            init();
        }




        TimeSpan ts_1sec = new TimeSpan(0, 0, 1);
        public int DefaultMaxRequest_1sec = 10;
        public const string RequestIP_Self = "self";

        CabalSoul _kernel;
        TargetMaxNum _maxnum = new TargetMaxNum();                  //最大连接数量规定
        Queue<RequestItem> _requests;                               //请求队列
        RequestIPList _requestlist;                                 //注册列表&队列
        public Missions RunningMission;                             //正执行的任务
        public Missions SleepingThread;                             //睡眠中线程
        public List<RequestItem> Responeses;                        //请求结果存放处
        public int MaxThreadNumber = 255;                           //最大线程数量
        public int MaxBufferNumber = 50;                            //最大缓存数量
        public int MaxMonoBuffer = 10;                              //独自缓存大小
        public int MaxResponseNumber = 255;                         //最大请求结果数量
        public Queue<RequestItem> Requests
        {
            get { return _requests; }
        }

        /// <summary>
        /// 部分函数会引起线程的睡眠（默认为True，会引发睡眠）
        /// </summary>
        public bool Reuqest_CauseThreadSleep = true;





        void init()
        {
            //实例化
            _requests = new Queue<RequestItem>();
            _requestlist = new Dictionary<string, Dictionary<string, IPTRegister>>();
            RunningMission = new Dictionary<Thread, RequestItem>();
            SleepingThread = new Dictionary<Thread, RequestItem>();
            Responeses = new List<RequestItem>();

            //读取TargetMaxNum列表
            Uri uri;//, num;
            string host;
            int num;
            foreach (XmlNode i in _kernel.Settings.ReadAllNodes("RequestMaxNumber"))
            {
                try
                {
                    uri = new Uri(i.SelectSingleNode("Server").InnerText);
                    num = int.Parse(i.SelectSingleNode("Number").InnerText);
                    host = uri.Host;
                    if (_maxnum.ContainsKey(host))
                        _maxnum.Remove(host);
                    _maxnum.Add(host, num);
                }
                catch { }
            }
        }

        public List<RequestItem> FindList(string RequestIP, string Target)
        {
            List<RequestItem> rtn = null;
            try
            {
                rtn = _requestlist[RequestIP][Target].Requests;
            }
            catch { }
            return rtn;
        }
        public IPTRegister FindRegister(string RequestIP, string Target)
        {
            IPTRegister rtn = null;
            try
            {
                rtn = _requestlist[RequestIP][Target];
            }
            catch { }
            return rtn;
        }

        public int GetThreadNumber(string RequestIP, string Target)
        {
            List<RequestItem> rtn = FindList(RequestIP, Target);
            if (rtn == null)
                return 0;
            else
                return rtn.Count;
        }

        /// <summary>
        /// 向请求管理器增加一个线程（当请求上限时会引发线程睡眠）
        /// </summary>
        public bool AddRequest(RequestItem item)
        {
            if (item.RequestIP == null || item.RequestIP == "")
                item.RequestIP = RequestIP_Self;
            string RequestIP = item.RequestIP;
            string Target = item.TargetAddress.Host;

            IPTRegister reg = FindRegister(RequestIP, Target);
            if (reg == null)
                reg = AddRegister(RequestIP, Target);

            List<RequestItem> lst = reg.Requests;  // FindList(RequestIP, Target);
            List<RequestItem> que = reg.BuffItems;

            if (_maxnum.ContainsKey(Target) == false)
                _maxnum.Add(Target, DefaultMaxRequest_1sec);

            //  请求数量                          缓冲数量                   全局缓冲数量                         全局线程数
            if (lst.Count <= _maxnum[Target] && que.Count < MaxMonoBuffer && _requests.Count < MaxBufferNumber && RunningMission.Count <= MaxThreadNumber)
            {

#if(debuglog)
                dbglogt.AppendLine(string.Format("#{0}:{1}<{2}> [V] RequestCount={3}<=Max={4},Queue={9}<=Max={10},Buff={5}<Max={6},Thread={7}<=Max={8}", Thread.CurrentThread.ManagedThreadId, "AddRequest", item.Describe, lst.Count, _maxnum[Target], _requests.Count, MaxBufferNumber, RunningMission.Count, MaxThreadNumber, que.Count, MaxMonoBuffer));
#endif

                _requests.Enqueue(item);
                que.Add(item);
                return true;
            }
            else
            {

#if(debuglog)
                dbglogt.AppendLine(string.Format("#{0}:{1}<{2}> [X] RequestCount={3},Max={4},Queue={9},Max={10},Buff={5},Max={6},Thread={7},Max={8}", Thread.CurrentThread.ManagedThreadId, "AddRequest", item.Describe, lst.Count, _maxnum[Target], _requests.Count, MaxBufferNumber, RunningMission.Count, MaxThreadNumber, que.Count, MaxMonoBuffer));
#endif

                //sleep
                if (Reuqest_CauseThreadSleep)
                {

#if(debuglog)
                    dbglogt.AppendLine(string.Format("#{0}:{1}", Thread.CurrentThread.ManagedThreadId, "Sleep(1000)"));
#endif
                    if (SleepingThread.ContainsKey(Thread.CurrentThread))
                        SleepingThread.Remove(Thread.CurrentThread);

                    SleepingThread.Add(Thread.CurrentThread,item);
                    //System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
                    System.Threading.Thread.Sleep(1000);
                }
                return false;
            }
        }
        /// <summary>
        /// 向请求管理器增加一个线程（当请求上限时返回false，否则返回true）
        /// </summary>
        public bool TryAddRequest(RequestItem item)
        {
            string RequestIP = item.RequestIP;
            string Target = item.TargetAddress.Host;
            if (RequestIP == null || RequestIP == "")
                RequestIP = RequestIP_Self;

            List<RequestItem> lst = FindList(RequestIP, Target);
            if (lst == null)
                lst = AddList(RequestIP, Target);
            if (lst.Count <= _maxnum[Target] && _requests.Count <= MaxBufferNumber && RunningMission.Count <= MaxThreadNumber)
            {
                //add
                //lst.Add(item);
                _requests.Enqueue(item);
                return true;
            }
            else
            {
                return false;
            }
        }
        public void RegisterRequest(RequestItem item)
        {
            lock (_requestlist)
            {
                IPTRegister reg = FindRegister(item.RequestIP, item.TargetAddress.Host);
                if (reg == null)
                    reg = AddRegister(item.RequestIP, item.TargetAddress.Host);

                reg.Requests.Add(item);
                reg.BuffItems.Remove(item); //因为获取请求了 所以要移除掉BUFF映射

#if(debuglog)
                dbglogt.AppendLine(string.Format("#{0}:{1}<{2}> RequestList.Count={3}", Thread.CurrentThread.ManagedThreadId, "RegRequest", item.Describe, reg.Requests.Count));
#endif
            }

            //RunningMission.Add(Thread.CurrentThread, item);
        }
        public void FixRequest(RequestItem oldItem, RequestItem newItem)
        {
            List<RequestItem> oldlst = FindList(oldItem.RequestIP, oldItem.TargetAddress.Host);
            oldlst.Remove(oldItem);

            List<RequestItem> newlst = AddList(newItem.RequestIP, newItem.TargetAddress.Host);
            newlst.Add(newItem);
        }
        public void RemoveRequest(RequestItem item)
        {
            try
            {
                List<RequestItem> lst = FindList(item.RequestIP, item.TargetAddress.Host);
                lst.Remove(item);
            }
            catch { }
        }

        List<RequestItem> AddList(string RequestIP, string Target)
        {
            if (_requestlist.ContainsKey(RequestIP))
            {
                if (_requestlist[RequestIP].ContainsKey(Target))
                    return _requestlist[RequestIP][Target].Requests;
                else
                {
                    IPTRegister iptr = new IPTRegister();
                    List<RequestItem> rtn = iptr.Requests;
                    _requestlist[RequestIP].Add(Target, iptr);
                    return rtn;
                }
            }
            else
            {
                IPTRegister iptr = new IPTRegister();
                List<RequestItem> rtn = iptr.Requests;
                TargetRequest tr = new Dictionary<string, IPTRegister>();
                tr.Add(Target, iptr);
                _requestlist.Add(RequestIP, tr);
                return rtn;
            }
        }
        IPTRegister AddRegister(string RequestIP, string Target)
        {
            if (_requestlist.ContainsKey(RequestIP))
            {
                if (_requestlist[RequestIP].ContainsKey(Target))
                    return _requestlist[RequestIP][Target];
                else
                {
                    IPTRegister iptr = new IPTRegister();
                    //List<RequestItem> rtn = iptr.Requests;
                    _requestlist[RequestIP].Add(Target, iptr);
                    return iptr;
                }
            }
            else
            {
                IPTRegister iptr = new IPTRegister();
                //List<RequestItem> rtn = iptr.Requests;
                TargetRequest tr = new Dictionary<string, IPTRegister>();
                tr.Add(Target, iptr);
                _requestlist.Add(RequestIP, tr);
                return iptr;
            }
        }

        public void SaveResponse(RequestItem item)
        {
            lock (Responeses)
            {
                if (Responeses.Count >= MaxResponseNumber)
                {
                    for (int i = 0; i < Responeses.Count - MaxResponseNumber; i++)
                    {
                        Responeses.RemoveAt(0);
                    }
                }
            }
            Responeses.Add(item);
        }
        public void TrimRegisterList(string RequestIP, string Target)
        {
            RequestList lst = FindList(RequestIP, Target);
            if (lst == null)
                return;

            //一秒请求清除
            try
            {
                while ((lst.Count > 0) && (lst[0].IsDone) && (DateTime.Now - lst[0].ResopnseTime > ts_1sec))
                {
                    lst.RemoveAt(0);
                }
            }
            catch { }
        }


        #region IDisposable 成员

        public void Dispose()
        {
            _requests.Clear(); _requests = null;
            _requestlist.Clear(); _requestlist = null;
            _maxnum.Clear(); _maxnum = null;
            SleepingThread.Clear(); SleepingThread = null;
            RunningMission.Clear(); RunningMission = null;
            Responeses.Clear(); Responeses = null;
            //this = null;

            GC.Collect();
        }

        #endregion
    }

    public class IPTRegister
    {
        public List<RequestItem> Requests = new List<RequestItem>();
        public List<RequestItem> BuffItems = new List<RequestItem>();
        //public int MaxBuff = 10;
        //public int MaxReuqesting = 10;
    }
}
